#include "NBT.h"
#include "TagType.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

_IMPLEMENT_NBTT(int, Int);
_IMPLEMENT_NBTT(double, Double);
_IMPLEMENT_NBTT(float, Float);
_IMPLEMENT_NBTT(char, Byte);

NBT::NBT(void)
{
	m_nTagType = NBTT_DEFAULT;
}
NBT::~NBT(void)
{
}
void* NBT::GetListData()
{
	// Return list element data
	return m_pData.get() + sizeof(char) + sizeof(int);
}
void NBT::SetListData(void *pData, int dataType, int nCount)
{
	int numBytes = nbtTypeSize[dataType] * nCount;
	// Create new memory to hold list elements
	m_pData = NBTData(new char[numBytes]);

	// Copy data to local container
	memcpy(m_pData.get(), pData, numBytes);
}
int NBT::GetListType()
{
	return *(m_pData.get());
}
int NBT::GetListLength()
{
	char typeSize = nbtTypeSize[GetListType()];
	return typeSize * GetListCount();
}
int NBT::GetListCount()
{
	char *lenStart = m_pData.get() + 1;
	return *((int*)lenStart);
}
int NBT::GetCompoundCount()
{
	return m_compoundTags.size();
}
int NBT::GetCompoundLength()
{
	int size = 0;
	vector<NBT>::iterator it = m_compoundTags.begin();
	for(; it != m_compoundTags.end(); it++)
	{
		size += it->GetNBTSize();
	}
	return size;
}
void NBT::AddCompoundElement(NBT element)
{
	m_compoundTags.push_back(element);
}
void NBT::ClearCompoundElements()
{
	m_compoundTags.clear();
}

void NBT::SetType(int type)
{
	//Do no change types if it's the same / preventing clearing
	if(type == m_nTagType)
		return;
	if((type > NBTT_MIN)  && (type < NBTT_MAX))
	{
		m_nTagType = type;
		switch(m_nTagType)
		{
		case NBTT_INT:
		case NBTT_BYTE:
		case NBTT_DOUBLE:
		case NBTT_FLOAT:
		case NBTT_SHORT:
		case NBTT_LONG:
			m_pData = NBTData(new char[nbtTypeSize[m_nTagType]]);
			break;
		case NBTT_END:
		case NBTT_COMPOUND:
		case NBTT_STRING:
		case NBTT_LIST:
			break;
		}
	}
}
int NBT::GetType()
{
	return m_nTagType;
}
int NBT::GetNBTSize()
{
	//Base Tag Size
	int sSize = nbtTypeSize[NBTT_BYTE]; // ID
	if(m_nTagType != NBTT_END) {
		sSize += m_strName.length() * sizeof(string::value_type); // Tag Name length (in bytes)
	}

	//Additional Tag Size
	switch(m_nTagType)
	{
	case NBTT_COMPOUND:
		sSize += GetCompoundLength(); // NBTSize of all compound elements in this compound
		break;
	case NBTT_LIST:
		sSize += nbtTypeSize[NBTT_BYTE]; // List Type
		sSize += nbtTypeSize[NBTT_INT]; // Length
	case NBTT_STRING:
		sSize += nbtTypeSize[NBTT_SHORT]; // Length
	case NBTT_ARRAY:
		sSize += nbtTypeSize[NBTT_INT]; // Length
	case NBTT_INT:
	case NBTT_BYTE:
	case NBTT_DOUBLE:
	case NBTT_FLOAT:
	case NBTT_SHORT:
	case NBTT_LONG:
		sSize += nbtTypeSize[m_nTagType]; // Size (in bytes) of element without header
		break;
	default:
		break;
	}
	return sSize;
}